No1. 喜傑獅「一讚折一元」事件:改 hosts 為什麼能繞過 Cloudflare?

2024 年喜傑獅(CJSCOPE)「一讚折一元」促銷引發的爭議,在二審判決出爐後又成為討論焦點。新聞常把事件濃縮成「消費者修改 hosts,繞過 Cloudflare 進入網站下單」,有些討論則直接稱為破解或入侵。

從技術角度看,這些說法把多個不同層次混在一起了。修改 hosts 不會破解 Cloudflare、不會改動公開 DNS,也不會取得伺服器權限;它只改變一台電腦將 hostname 解析成哪個 IP。真正的問題是:Cloudflare 後方的 Origin 仍可從 Internet 直接連線,而且應用程式仍接受訂單、寫入資料並寄出通知。

Cloudflare 保護的是「經過 Cloudflare 的流量」。Origin 若仍接受任意來源直接連線,知道 Origin IP 的 client 就可能建立另一條不經 Cloudflare 的連線路徑。

以下分析不判定個案的法律責任,也不推測當事人取得 Origin IP 的方法。重點是釐清 DNS、TCP、TLS SNI、HTTP Host、Reverse Proxy 與訂單狀態之間的關係。

喜傑獅「一讚折一元」事件與證據範圍

二審判決記載,喜傑獅於 2024 年 11 月 24 日發布促銷活動,貼文最後累積約 1.7 萬個讚。業者主張網站出現異常流量及 DDoS 警告,因此在 11 月 25 日 21:06 通知代管公司進行網站關閉操作;消費者則在當日 21:57 左右,以 Linux 修改 hosts 的方式連入網站、送出訂單,並收到系統通知。

判決進一步記載,21:06 的操作是修改 Cloudflare 端的設定以封鎖一般訪問請求,並沒有停止 Origin 主機。該操作之後,系統仍產生 516 筆訂單。這兩項資訊是整起事件最重要的技術背景:臺灣士林地方法院 114 年度消小上字第 3 號判決。新聞對判決結果及主要過程另有摘要,可參考聯合新聞網的事件報導

事件時間線

時間(UTC+8) 公開資料記載 技術意義
2024-11-24 晚間 發布「一讚折一元」促銷 流量與訂單需求上升
2024-11-25 21:06 代管公司調整 Cloudflare 設定 正常入口受到限制,Origin 主機未停止
2024-11-25 21:32 消費者私訊表示官網無法進入 當事人知道正常連線路徑異常
2024-11-25 21:57 消費者以 Linux 修改 hosts 後送出訂單 請求以不同路徑到達仍在運作的應用程式
關閉操作後 系統仍產生 516 筆訂單 Edge 層措施沒有同步停止所有訂單副作用
2024-11-26 01:07 相關教學影片發布 晚於本案訂單,不是本案當事人的學習來源
2025-09-30 第一審判決 法院認定買賣契約成立
2026-08-12 第二審判決 廢棄原判決,認定系統通知不足以表示業者承諾

已確認事實、技術推論與未知事項

事件分析必須區分公開證據與架構推論,否則很容易把一個 Origin 暴露問題擴張成沒有證據支持的「主機遭入侵」。

證據層級 內容
公開資料可確認 當事人修改本機 hosts;Origin 主機未在 21:06 停止;系統接受訂單並產生通知;關閉操作後仍有訂單產生
依連線結果可合理推論 Origin 當時可從公網到達;Web Server 能以正式 hostname 選到網站;至少一條訂單寫入路徑仍啟用
公開資料不足 21:06 究竟修改哪一項 Cloudflare 設定;Origin IP 如何被發現;TLS、Firewall 與 VirtualHost 的完整設定;516 筆訂單各自使用哪條連線路徑
僅屬一方主張 DDoS 是否發生、流量規模、來源及持續時間

二審處理的是自動通知能否構成法律上的意思表示;工程分析處理的是另一個問題:營運方已決定停止接單,系統為何仍可完成訂單寫入及通知。法律效果與系統是否正確執行營運狀態,不能視為同一件事。

Cloudflare Reverse Proxy 與 Origin 資料流

Cloudflare DNS 記錄開啟 Proxy,也就是常說的橘雲後,訪客通常不會從 DNS 得到 Origin IP,而會得到 Cloudflare Anycast IP。一般 HTTP 流量的路徑如下:

Visitor
  │ ① DNS 回傳 Cloudflare IP
  ▼
Cloudflare Edge
  │ ② WAF、DDoS mitigation、Rate Limiting、Bot 管理、Cache
  ▼
VM Origin
  │ ③ Web Servewr(Nginx or Apache2 or ...) 將請求交給應用程式
  ▼
Application → Database → Mail/Queue/Payment

這裡不是一條從瀏覽器一路延伸到 Origin 的單一連線,而是至少兩條獨立連線:

1. Visitor 與 Cloudflare Edge 之間的連線。

2. Cloudflare Edge 與 Origin 之間的連線。

Cloudflare 的 WAF、Rate Limiting 或維護規則,只能處理第一條連線確實到達 Cloudflare 的流量。若 client 直接對 Origin IP 建立 TCP 連線,Cloudflare 不在封包路徑上,自然沒有機會判斷或封鎖該請求。

這不代表 Cloudflare Proxy 沒有效果。橘雲仍能隱藏目前 DNS 回應中的 Origin IP、吸收正常路徑的攻擊流量,並在 Edge 執行安全政策;問題在於「正常 DNS 指向 Cloudflare」不等於「Origin 只接受 Cloudflare」。前者是路徑引導,後者才是存取控制。

Cloudflare 官方也要求 Origin 明確拒絕非 Cloudflare 或非可信來源流量,並建議檢查 DNS-only 記錄、郵件服務及歷史 DNS 是否暴露 Origin IP;已暴露過的 Origin IP 應評估輪替。Cloudflare:Protect your origin server

hosts 覆寫對名稱解析與連線目的地的影響

Linux 的 `/etc/hosts` 是靜態 hostname-to-IP 對照表。每一行將 IP 與一個或多個 hostname 關聯,例如:

203.0.113.10 www.example.com

203.0.113.0/24RFC 5737 保留給文件範例的網段,不代表任何真實 Origin。example.com 也是保留給文件使用的網域。

Ubuntu 上的名稱解析順序由 /etc/nsswitch.confhosts: 欄位控制。常見設定會先查本機檔案,再查 DNS,但實際順序仍應以系統設定為準:

grep '^hosts:' /etc/nsswitch.conf

應用程式若使用作業系統的 resolver,便可能採用 /etc/hosts 的結果。修改通常立即生效,但應用程式或本機 resolver 若有 cache,仍可能需要重新連線或清除快取。/etc/hosts 的格式與行為可參考 Linux hosts(5) manual

有一個常被忽略的差異:

getent ahosts www.example.com 經過 Linux Name Service Switch,比較接近一般程式看到的解析結果。

dig +short www.example.com 直接查詢 DNS,不會用來證明 /etc/hosts 是否生效。

因此,修改 hosts 後看到 dig 仍回覆 Cloudflare IP 並不矛盾;瀏覽器或 curl 經由系統解析時,仍可能使用本機指定的 Origin IP。

DNS、TCP、TLS 與 HTTP 的分層結果

正常路徑: www.example.com → Cloudflare IP → Cloudflare → Origin
覆寫路徑: www.example.com → Origin IP ───────────────→ Origin
項目 正常路徑 覆寫後
URL hostname www.example.com www.example.com,不變
名稱解析結果 Cloudflare IP 本機指定的 Origin IP
TCP destination Cloudflare IP:443 Origin IP:443
TLS SNI www.example.com www.example.com,不變
憑證 hostname 驗證 驗證 www.example.com 仍驗證 www.example.com
HTTP/1.1 Host www.example.com www.example.com,不變
HTTP/2 :authority www.example.com www.example.com,不變

這就是直連可能成功的關鍵:只有「目的 IP」被換掉,網站識別名稱仍然保留。

Nginx 與 Apache2 常在同一個 IP 上服務多個網站。TLS 握手時,Web Server 可依 SNI 選擇憑證與 TLS VirtualHost;進入 HTTP 後,再依 Host 或 HTTP/2 :authority 選擇網站。只要 Origin 上仍配置正式 hostname,直連請求就可能被送進正式應用程式。

直接把 URL 寫成 https://203.0.113.10/ 並不等價。此時 SNI、憑證驗證名稱及 HTTP request authority 都可能變成 IP,導致預設 VirtualHost 或憑證不符。只加 -H 'Host: www.example.com' 也不完整,因為它沒有改變 TCP destination,HTTPS 的 SNI 與憑證驗證名稱也不一定一致。

修改 hosts 本身不會:

– 改動權威 DNS 或其他使用者的解析結果。

– 取得 Shell、後台帳號或資料庫權限。

– 穿透 GCP Firewall、Nginx/Apache2 ACL 或 mTLS。

– 關閉 Cloudflare,或改變 Cloudflare 帳戶內的設定。

它只是把既有的另一個入口暴露出來。如果 Origin 已拒絕非 Cloudflare 來源,這個方法只會得到 timeout、connection refused、TLS failure 或 HTTP deny。

curl --resolve 的連線重現與封包語意

curl --resolve 可以在不修改 /etc/hosts、不需要 root 權限的情況下,為指定的 hostname:port 覆寫本次執行使用的 IP。curl 官方把它描述為命令列上的 /etc/hosts 替代方式:curl --resolve 文件

Direct-origin 示範只使用文件 IP 或本機 loopback,用來觀察連線語意。正常 HTTPS 路徑中的 www.example.com 是欄位示例,執行前應換成自有且已開啟 Cloudflare Proxy 的 hostname。實際 Origin 測試只應在自有或明確授權的系統進行。

Step 1:區分 DNS 回應與作業系統解析結果

dig +short www.example.com

getent ahosts www.example.com

第一個命令觀察 DNS server 的回答,第二個命令觀察 Ubuntu Name Service Switch 提供給應用程式的結果。在沒有本機覆寫時,兩者通常相近;有 /etc/hosts、mDNS 或其他 NSS source 時,結果可能不同。

Step 2:觀察正常 HTTPS 連線

curl --verbose \
  --noproxy '*' \
  --connect-timeout 3 \
  --output /dev/null \
  'https://www.example.com/'

將 www.example.com 換成自有且已開啟 Cloudflare Proxy 的 hostname,verbose output 會顯示實際連線 IP、TLS 憑證及 HTTP response headers。CF-Ray 或 server: cloudflare 可作為流量經過 Cloudflare 的觀察線索,但不應單獨當成安全邊界的證明。

Step 3:保留 hostname 並覆寫 destination IP

curl --verbose \
  --noproxy '*' \
  --connect-timeout 3 \
  --resolve 'www.example.com:443:203.0.113.10' \
  --output /dev/null \
  'https://www.example.com/'

這個命令表達的連線意圖是:

URL hostname       = www.example.com
TCP destination    = 203.0.113.10:443
TLS SNI            = www.example.com
Certificate name   = www.example.com
HTTP authority     = www.example.com
Public DNS result  = 本次連線不採用

--resolve 的第一個 hostname 必須與 URL hostname 相符,port 也必須與實際連線 port 相符。HTTPS 預設使用 443;同一 hostname 的 80 與 443 若都要測試,需要各自建立一筆 mapping。--noproxy '*' 則避免環境中的 HTTP/HTTPS Proxy 改變實際連線路徑。

範例 IP 不應出現在公共 Internet 路由,執行後很可能 timeout,這是正常結果。不要加入 -k 或 --insecure 讓命令表面成功,因為跳過 TLS 驗證會掩蓋「Origin 是否提供可信且 hostname 相符的憑證」這個成立條件。

Step 4:在 Ubuntu 本機完成可觀察驗證

終端機 A 啟動一次性 HTTP server:

python3 -m http.server 18080 --bind 127.0.0.1

終端機 B 以不存在於 DNS 的 hostname 連回本機:

curl --noproxy '*' \
  --verbose \
  --resolve 'shop.demo.invalid:18080:127.0.0.1' \
  --output /dev/null \
  'http://shop.demo.invalid:18080/'

--noproxy '*' 用來避免環境中的 HTTP Proxy 接手連線。curl output 應出現類似內容:

* Connected to shop.demo.invalid (127.0.0.1) port 18080
> Host: shop.demo.invalid:18080

第一行證明 TCP 實際連到 127.0.0.1,第二行證明 HTTP hostname 仍是 shop.demo.invalid。同一個 request 同時保有「指定 IP」與「原 hostname」,已足以重現事件所使用的連線原理。完成後在終端機 A 按 Ctrl+C 停止 server。

本機 HTTP 示範刻意不加入 TLS,目的是讓連線結果可重現且不需要建立測試憑證。真實 HTTPS Origin 還會多出 SNI、憑證信任、有效期限及 hostname 驗證,不能從 HTTP 成功直接推論 HTTPS 也會成功。

Origin Direct Access 的成立條件

修改 hosts 或使用 curl --resolve 只是選擇 destination IP。要讓請求一路進入正式應用程式,下列條件必須同時成立:

條件 Origin 必須具備的狀態 缺少條件時的常見結果
Origin IP 已知 Client 有正確且仍有效的位址 連到錯誤主機或 timeout
公網路由存在 VM 有 External IP 或其他 public ingress 無法建立連線
網路 Firewall 放行 GCP VPC Firewall 允許該來源連入 80443 TCP timeout
Web Server listener 放行 Nginx/Apache2 接受該來源及 port connection refused 或 403
VirtualHost 相符 SNI 與 request authority 能選到正式站台 預設站台、421 或 TLS 錯誤
TLS 條件成立 憑證、協定及 hostname 驗證可完成 TLS handshake 或憑證驗證失敗
Application 接受操作 訂單 API、Session、CSRF、庫存及業務規則仍允許寫入 4xx5xx,不建立訂單
下游副作用啟用 Database、Queue、Mail、Payment 等仍執行 只留下部分狀態,不完成流程

這是一組 AND 條件,不是只要知道 IP 就一定成功。任一層正確拒絕,都能阻止事件中的完整結果。

這也說明為何 Origin IP 外洩與漏洞利用不能劃上等號。IP 是定位資訊;真正的弱點是系統仍將該 IP 當作無條件可進入的正式入口。反過來說,只隱藏 IP 也不能取代 Firewall、mTLS 或 private ingress,因為歷史 DNS、DNS-only 子網域、郵件服務、憑證紀錄或其他基礎設施都可能再次暴露 Origin。

Origin 暴露與控制面不一致

事件不是單一設定錯誤,而是 Edge、Origin 與 Application 三個層次採用不同的服務狀態。

層次 當時可觀察的狀態 產生的結果
Cloudflare Edge 正常訪問受到封鎖 多數訪客認為網站已關閉
Origin ingress 主機未停止,且至少一條公網直連路徑有效 請求可避開 Edge 控制
Nginx/Apache2 正式 hostname 仍能對應網站 Direct request 進入正式應用程式
Application 訂單 command 仍可執行 建立訂單資料
Notification 自動通知仍啟用 對外送出訂單相關訊息

IP 不公開不是存取控制

Origin IP 不出現在目前的 Proxied DNS 回應中,可以降低被直接發現的機率,但這是資訊隱藏,不是授權機制。可靠的控制必須讓非預期來源即使知道 IP,也無法完成連線或通過身分驗證。

若 Origin 對全 Internet 開放,Direct request 可能略過:

  • Cloudflare WAF 規則。
  • Rate Limiting 與 Bot 管理。
  • Cloudflare DDoS mitigation。
  • Edge Access policy、Redirect 或維護頁。
  • 只存在 Cloudflare 端的 Cache 與 Header transformation。

能略過上述控制,不等於已取得伺服器控制權。就公開資料而言,可確認的是非預期路徑成功執行訂單;沒有足夠證據證明資料外洩、SQL injection、帳號接管、任意程式碼執行或 Shell access。較精確的技術定性是 Origin exposure 與 security control bypass,不是已證實的主機入侵。

Forwarded Header 不能自行證明來源

公開 Origin 也會影響真實訪客 IP 的信任模型。CF-Connecting-IPX-Forwarded-For 都是 HTTP Header;任意 client 直連 Origin 時,也能自行建立同名 Header。Web Server 只有在 TCP peer 已確認是 Cloudflare IP,或連線已通過可信的 mTLS/Tunnel 身分驗證後,才能採信這些欄位。

因此,來源限制與 Real IP 還原有固定順序:先確認誰是可信 Proxy,再接受它提供的訪客 IP。單純把 CF-Connecting-IP 寫進 access log,不能證明 request 經過 Cloudflare。

服務停止的跨層控制

「網站顯示維護頁」與「系統停止接單」是兩個不同的目標。前者是呈現層結果,後者必須停止會改變狀態的 command 及其副作用。

可靠的停止程序應依下列順序執行。

Step 1:Application 拒絕新的狀態變更

建立 server-side order_acceptance_state 或 checkout_enabled,並讓所有訂單入口共用同一份權威狀態。檢查必須在 server side 執行,不能只靠前端隱藏按鈕或 JavaScript。

訂單狀態檢查與資料寫入還要處理並行競爭。概念上的 transaction 應接近:

BEGIN
  lock and read order_acceptance_state
  if state != OPEN: reject with ORDERING_DISABLED
  validate price, promotion, stock and idempotency key
  insert order with RECEIVED status
COMMIT

若先檢查、隔一段時間才寫入,切換關閉狀態的瞬間仍可能有 request 穿過檢查並在稍後 commit。使用 transaction、lock 或具相同一致性保證的設計,才能定義清楚的停止時間點。

Step 2:停止或隔離下游副作用

Database 新增一筆資料只是訂單流程的其中一步。付款、庫存保留、寄信、簡訊、出貨工作與第三方 Webhook 也必須遵守相同狀態。

緊急停止時,可將切換時間後的工作標記為 QUARANTINED,暫停 consumer 或在執行前重新檢查 incident state。已進入 Queue 的舊訊息不會因 Cloudflare 顯示維護頁而自動消失。

Step 3:Cloudflare Edge 回覆維護狀態

Application 已停止狀態變更後,再由 Cloudflare 回覆維護頁或適當的 503 Service Unavailable,降低 Origin 負載並向一般訪客提供一致訊息。若能估計恢復時間,可加上 Retry-After

DNS 變更不適合作為唯一的緊急停止開關,因為 resolver cache、TTL、既有 keep-alive connection 及未經 DNS 的 direct path 都可能延續一段時間。

Step 4:Origin ingress 維持來源限制

GCP Firewall、Nginx/Apache2 ACL、AOP 或 Tunnel 不應只在事件發生時臨時設定。正常營運期間就應阻止非 Cloudflare direct access,維護期間則繼續維持相同限制。

Step 5:驗證正常路徑與 Origin 路徑

驗證不能只開瀏覽器看到維護頁。自有測試環境至少要確認:

  1. 正常 hostname 經 Cloudflare 回覆預期的維護狀態。
  2. 使用 curl --resolve 指向自有 Origin 時,非可信來源在 TCP、TLS 或 HTTP 層被拒絕。
  3. 繞過前端畫面的訂單 API 仍由 Application 回覆 ORDERING_DISABLED,且 Database 沒有新增訂單。
  4. Queue、Mail、Payment 與庫存沒有產生新的副作用。
  5. Cloudflare、Origin、Application、Database 與 Worker log 能以 request ID 或 order ID 對應。

驗證 curl --resolve 時只應對自有或書面授權的 Origin 執行,並使用不會改變正式資料的 health endpoint 或 staging environment。

Step 6:保留證據與設定版本

事件期間應保存 Cloudflare Security Events、Audit Log、Origin access/error log、Application log、Database audit、Queue 記錄與設定變更時間。敏感 Cookie、Authorization、付款資料與個資不得直接寫入一般 log。

沒有跨層時間戳與 request ID,只能知道「曾經有訂單」,無法可靠回答 request 經過哪條路徑、在哪個控制點被接受,以及 516 筆訂單中哪些與 direct access 有關。

Cloudflare Origin 防護方案與實作範圍

Origin 保護沒有一個設定能取代所有其他層。不同控制回答的是不同問題:

控制 解決的問題 不解決的問題
Proxied DNS 讓一般流量先到 Cloudflare,隱藏目前 DNS 回應中的 Origin IP 不強制 Origin 拒絕直連
Cloudflare IP allowlist 在 GCP 或 Web Server 只允許 Cloudflare 網段連入 不驗證特定 Cloudflare 帳戶;不停止 Application 副作用
Authenticated Origin Pulls(AOP) Origin 以 client certificate 驗證連線來自 Cloudflare 不取代 Application 授權或 kill switch
Cloudflare Tunnel Origin 主動向 Cloudflare 建立 outbound-only connection,不保留 public inbound listener 需要安裝及維運 cloudflared;不與 AOP 疊加
Full (strict) Cloudflare 驗證 Origin certificate 的信任、期限及 hostname 不驗證直連 Origin 的 client 是 Cloudflare
Application kill switch 停止訂單、付款、寄信等業務副作用 不提供 DDoS 或網路層保護

GCP 單一 VM 的建議基線

以「Cloudflare → GCP Compute Engine VM → Nginx/Apache2」的簡單架構來說,可採用以下組合:

  1. DNS 記錄啟用 Cloudflare Proxy。
  2. 已公開過的 Origin IP 評估輪替,並移除會暴露同一 IP 的 DNS-only 記錄或共用郵件服務。
  3. GCP VPC Firewall 的 80443 只允許 Cloudflare 官方 IPv4、IPv6 CIDR;沒有使用 IPv6 時,確認 VM、DNS 與 listener 都沒有額外 IPv6 入口。
  4. Nginx/Apache2 只配置必要 hostname,未知 Host 不送進正式 Application。
  5. Cloudflare 到 Origin 使用 Full (strict),讓 Cloudflare 驗證 Origin certificate。
  6. 需要更強的 Origin 身分驗證時,加入 zone-level 或 per-hostname AOP 自有憑證;Cloudflare 提供的 Global AOP 憑證只能證明 request 來自 Cloudflare network,不能證明來自特定帳戶。
  7. 若不需要 public ingress,改用 Cloudflare Tunnel,從架構上移除可被直連的公開 listener。Tunnel 已使用 connector credential 驗證連線,與 AOP 的工作模式不同。
  8. Application 保留獨立 kill switch,並讓訂單、付款、Queue 及通知共用相同 incident state。
  9. Access log 同時保留實際 peer IP 與通過 Trusted Proxy 驗證後的 visitor IP,避免事後只剩無法還原路徑的單一欄位。
  10. 從外部網路定期執行安全的 direct-origin negative test,確認未授權路徑持續失敗。

Cloudflare 將 IP allowlist 列為網路層 Origin 防護,並要求明確封鎖所有非 Cloudflare 或非可信來源流量;AOP 則在 Full/Full (strict) 之上增加 client certificate 驗證。Cloudflare Origin 防護文件Authenticated Origin Pulls 文件

Full (strict) 的方向恰好相反:它是 Cloudflare 作為 client 時驗證 Origin server certificate,要求憑證未過期、由公開 CA 或 Cloudflare Origin CA 簽發,且 CN/SAN 符合 hostname。它保護 Cloudflare-to-Origin TLS,不是 Origin ingress allowlist。Cloudflare:Full (strict)

Origin 若只提供 Cloudflare Origin CA certificate,一般瀏覽器或未加入該 CA 的 curl 直連時通常會因不信任簽發者而失敗;這仍不是來源限制。網路入口依然存在,Origin 也沒有藉此驗證連入的 client 是不是 Cloudflare,因此不能用 client 端預設不信任取代 Firewall、AOP 或 Tunnel。

喜傑獅事件的技術結論可以濃縮成一句話:Edge 顯示關閉,不代表 Origin 與 Application 已停止。 完整防護必須同時限制 Origin 來源、驗證可信 Proxy、保護 Cloudflare-to-Origin TLS,並由 Application 掌握真正的業務停止狀態。即使 Origin IP 再次被發現,系統也不應因此多出一條可完成交易的未授權路徑。